/*****************************************************************************/
/*                        >>> func_rutinas.c-- <<<                           */
/*	Trabajo Practico 2do. cuatrimestre 2011                                  */
/*	TP:"FUSELAJE"                                                            */
/*	GRUPO: Reduce Fat Fast                                                   */
/*	INTEGRANTES: Emanuel Genovese                                            */
/*               Federico Gabriel Garcia                                     */
/*               Federico Pioli                                              */
/*               Esther Insfrain                                             */
/*               Luciano Bagattin                                            */
/*	Fecha UM:                                                                */
/*****************************************************************************/
/*****************************************************************************/
/*		        	HEADERS					                                 */
/*****************************************************************************/
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <sys/timeb.h>
#include "../headers/func_rutinas.h"
#include "../headers/variables_globales.h"
#include "../headers/constantes.h"
#include "constants_commons.h"
#include "math.h"

/******************************************************************************/
/* Nombre de Funcion: pInializarCache                                         */
/* Parametros: vecCache:vector de 10 posiciones                               */
/* Descripcion: Procedimiento qeu inicializa un vector de 10 posiciones       */
/******************************************************************************/
void pInicializarCache(void) {
	/* declaracion de variables locales*/
	int i;
	/*fin declaracion de variables locales*/
	vecCache = (stVecCache*) malloc(10 * sizeof(stVecCache));
	for (i = 0; i < 20; i++) {
		vecCache[i].iNumSector = -1;
		vecCache[i].iPista = -1;
		memset(vecCache[i].info, '\0', 512);

	} //fin del for

} //fin del pInicializarCache
/******************************************************************************/
/* Nombre de Funcion: fBuscaEInsertaPista                                     */
/* Parametros: iPista:pista a insertar o buscar                               */
/* Descripcion: Funcion que busca una pista en la lista doblemente enlazada   */
/*              en caso de existir devuelve el puntero a ese nodo y si no lo  */
/*              inserta                                                       */
/******************************************************************************/

struct stNodoPista * fBuscarEInsertaPista(int iPista, int iCampo) {
	stNodoPista *ptrNuevo, *result;
	ptrNuevo = (stNodoPista *) malloc(sizeof(stNodoPista));
	stNodoPista **aux = NULL;

	/*armo el nodo */
	ptrNuevo->iNumPista = iPista;
	ptrNuevo->lPedidosFte = NULL;
	ptrNuevo->lPedidosFin = NULL;
	ptrNuevo->Ant = NULL;
	ptrNuevo->Sgte=NULL;
	ptrNuevo->iCantPedidos = 0;

	/*Cargamos el primer nodo de la lista*/
	if (iCampo == 1) {
		if (lPista == NULL) {
			lPista = ptrNuevo;
			result = ptrNuevo;
		} else if (iPista < lPista->iNumPista) {
			/*Lo inserta por delante*/
			ptrNuevo->Sgte = lPista;
			lPista->Ant = ptrNuevo;
			lPista = ptrNuevo;
			result = ptrNuevo;

		} else {
			lPista = *aux;
			aux = &lPista;
			while (*aux != NULL && (*aux)->iNumPista < iPista)
				aux = &(*aux)->Sgte;
			/*Si lo encuentra devuelve el puntero al nodo encontrado*/
			if ((*aux)->iNumPista == iPista) {
				result = (*aux);
				free(ptrNuevo);
			} else {
				/*lo inserta por atras y lo devuelve al puntero.*/
				ptrNuevo->Sgte = *aux;
				ptrNuevo->Ant = (*aux)->Ant;
				(*aux)->Ant = ptrNuevo;
				*aux = ptrNuevo;
				result = ptrNuevo;
			}

		}
	} else {
		if (lPista2 == NULL) {
			lPista2 = ptrNuevo;
			result = ptrNuevo;
		} else if (iPista < lPista2->iNumPista) {
			/*Lo inserta por delante*/
			ptrNuevo->Sgte = lPista2;
			lPista2->Ant = ptrNuevo;
			lPista2 = ptrNuevo;
			result = ptrNuevo;

		} else {
			lPista2 = *aux;
			aux = &lPista2;
			while (*aux != NULL && (*aux)->iNumPista < iPista)
				aux = &(*aux)->Sgte;
			/*Si lo encuentra devuelve el puntero al nodo encontrado*/
			if ((*aux)->iNumPista == iPista) {
				result = (*aux);
				free(ptrNuevo);
			} else {
				/*lo inserta por atras y lo devuelve al puntero.*/
				ptrNuevo->Sgte = *aux;
				ptrNuevo->Ant = (*aux)->Ant;
				(*aux)->Ant = ptrNuevo;
				*aux = ptrNuevo;
				result = ptrNuevo;
			}

		}

	}

	return result;
}

/******************************************************************************/
/* Nombre de Funcion: fAgregarPedido                                          */
/* Parametros: iSocket:socket                                                 */
/*             iSector: sectores del pedido                                   */
/*             itipoOp: tipo de operacion lectura o escritura                 */
/* Descripcion: Procedimiento que carga el nodo correspondiente a una pista   */
/*              pistas del disco                                              */
/******************************************************************************/

void fAgregarPedido(int iSocket, int iSector, int iTipoOp, char *info,
		int iCampo, char *sDescriptorOriginal) {
	/*declaracion de variables locales*/
	stNodoPista *p = (stNodoPista *) malloc(sizeof(stNodoPista));
	stNodoPedido *m = (stNodoPedido*) malloc(sizeof(stNodoPedido));
	stNodoPedido *aux, *ant;

	int iPista;
	/*fin de declaracion de variables locales*/
	/*Vemose segun el iCampo donde tenemos que cargar */
	if (iCampo == 1) {
		p = lPista;
	} else {
		p = lPista2;

	}
	iPista = (int) (iSector / iSectores);
	p = fBuscarEInsertaPista(iPista, iCampo);
	m->iNumSector = iSector % iSectores;
	m->iSocket = iSocket;
	m->iTipoOperacion = iTipoOp;
	strcpy(m->sDescriptorOriginal, sDescriptorOriginal);
	memset(m->info, '\0', 512);
	if (iTipoOp == ESCRITURA) {
		strcpy(m->info, info);
	}
	m->Sgte = m;
	p->iCantPedidos++;
	if (iCampo == 1) {
		iCantPedidosCola1++;
	} else {
		iCantPedidosCola2++;

	}
	if (p->lPedidosFte == NULL) {

		p->lPedidosFte = m;
		p->lPedidosFin = m;
	} else {
		aux = p->lPedidosFte;
		ant = p->lPedidosFte;
		while (aux != NULL && aux->iNumSector < m->iNumSector) {
			ant = aux;
			aux = aux->Sgte;
		}
		if (aux->iNumSector <= m->iNumSector) {
			aux->Sgte = m;
			p->lPedidosFin = m;
		} else {
			ant->Sgte = m;
			m->Sgte = aux;
		} //fin del if
	} //fin del if
	iSacado = 1;

} //fin de fAgregarPedido

/******************************************************************************/
/* Nombre de Funcion: fSacarPedidoEnCola                                      */
/* Parametros: iSocket:socket                                                 */
/*             iSector: sectores del pedido                                   */
/*             itipoOp: tipo de operacion lectura o escritura                 */
/* Descripcion: Procedimiento que carga el nodo correspondiente a una pista   */
/*              pistas del disco                                              */
/******************************************************************************/

stNodoPedido * fSacarPedidoEnCola(stNodoPista *lP, int iCampo) {
	int iPistaActual;
	stNodoPista *pActual, *pAnterior;
	stNodoPedido *aux, *k;
	int iCantPedidos = 0;

	iPistaActual = (int) (iPosicionCabezal / iSectores);
	if (iCampo == 1) {
		iCantPedidos = iCantPedidosCola1;
	} else {
		iCantPedidos = iCantPedidosCola2;

	}

	if (lP == NULL) {
		if (iCampo == 1) {
			iEstadoCola1 = WAIT;
		} else {
			iEstadoCola1 = ACTIVE;

		}

	} else {
		if (iCantPedidos > 0) {
			switch (iEstadoCabezal) {
			case ASCEND:
				pActual = lP;
				pAnterior = lP;
				while (pActual != NULL && pActual->iNumPista < iPistaActual) {
					pAnterior = pActual;
					pActual = pActual->Sgte;
				}
				if (pActual == NULL) {
					iEstadoCabezal = DESCEND;
					iPosicionCabezal=iPosicionCabezal+iSectores*((iCilindros-1)-iPistaActual);

				} else if (pActual->iNumPista == iPistaActual) {

						k = pActual->lPedidosFte;
						aux = fBuscarMinNodoLista(k, 1);
						if (aux == NULL	)
							aux = fBuscarMinNodoLista(k, 0);
						fExtraerNodoLista(k, aux);
						pActual->iCantPedidos--;
						if (iCampo == 1) {
							iCantPedidosCola1--;
						} else {
							iCantPedidosCola2--;
						}
						if (pActual->iCantPedidos == 0) {
						    pAnterior = pActual->Sgte;
							if (pActual->Sgte != NULL) {
							    pActual->Sgte->Ant = pAnterior;
							}
							free(pActual);
						}

				}else if (pActual->iNumPista > iPistaActual){
					if (iPistaActual < (iCilindros - 1)) {
					   iPosicionCabezal += iSectores;
					}

				}





				break;
			case DESCEND:
				pActual = lP;
				pAnterior = lP;
				while (pActual != NULL) {
					pAnterior = pActual;
					pActual = pActual->Sgte;

				} //FIN DEL WHILE
				while (pAnterior != NULL && pAnterior->iNumPista > iPistaActual) {
				   pActual = pAnterior;
				   pAnterior=pAnterior->Ant;
				 }
				if (pAnterior == NULL) {
					iEstadoCabezal = ASCEND;
					iPosicionCabezal=iPosicionCabezal-(iSectores*iPistaActual);
				} else if (pAnterior->iNumPista == iPistaActual) {

						k = pAnterior->lPedidosFte;
						aux = fBuscarMinNodoLista(k, 1);
						if (aux == NULL)
							aux = fBuscarMinNodoLista(k, 0);
						fExtraerNodoLista(k, aux);
						pAnterior->iCantPedidos--;
						if (pAnterior->iCantPedidos == 0) {
						    pActual->Ant = pAnterior->Ant;
							if (pActual->Ant != NULL) {
								pAnterior->Ant->Sgte = pActual;
							 }
						 }
						if (pAnterior->iCantPedidos == 0) {
							pActual = pAnterior->Ant;
						   if (pAnterior->Ant != NULL) {
							 pAnterior->Ant->Sgte = pActual;
						   }
							free(pAnterior);
						}

				} else if (pAnterior->iNumPista < iPistaActual) {
					if (iPistaActual < (iCilindros - 1)) {
						 iPosicionCabezal -= iSectores;
					}


				}

				break;
			} //fin del switch

		}
	}

	return aux;

}

/******************************************************************************/
/* Nombre de Funcion: fExtraerNodoLista                                       */
/* Parametros: lista:lista de pedidos                                         */
/*               valor:puntero al nodo que se desea sacar de la lista         */
/* Descripcion: Procedimiento que encarga de sacar el nodo de la lista        */
/******************************************************************************/

int fExtraerNodoLista(stNodoPedido *lista, stNodoPedido * valor) {
	stNodoPedido * ext1;

	ext1 = lista;
	do {
		if (lista->Sgte->iNumSector != valor->iNumSector)
			lista = lista->Sgte;
	} while (lista->Sgte->iNumSector != valor->iNumSector && lista != ext1);
	if (lista->Sgte->iNumSector == valor->iNumSector
			&& lista->Sgte->iUsado == valor->iUsado) {
		if (lista == (lista)->Sgte) {
			// Borrar toda la lista

			free(lista);
			lista = NULL;
		} else {
			// Si la lista tiene más de un nodo, borrar el nodo  de valor v
			ext1 = (lista)->Sgte;
			lista->Sgte = ext1->Sgte;
			free(ext1);

		}
	}
	return 1;
}

/********************************************************************************/
/* Nombre de Procedimiento: fBuscarMinNodoLista                                 */
/* Parametros:	ListaPedidos: lista de pedidos circular                         */
/*				Mayores: Flag que marca si tiene que buscar el minimo mayores   */
/*                a la posicion del cabezal en caso de que este en 1 o menores  */
/*                en el caso que este en 0                                      */
/* Descripcion: Procedimiento que se encarga de buscar el nodo que esta mas     */
/*              cerca del cabezal y el mas chico de toda la lista               */
/********************************************************************************/
stNodoPedido * fBuscarMinNodoLista(stNodoPedido * ListaPedidos, int Mayores) {
	/*declaracion de variables locales*/
	struct stNodoPedido * aux, *actual, *pMin = NULL;
	float min = 150000.0, fVariable;
	/*fin de la declaracion de variables locales*/
	aux = ListaPedidos;
	actual = aux;
	if (ListaPedidos == NULL) {
		return NULL;
	} else {
		if (ListaPedidos->iUsado == 0) {
			min = (float) ListaPedidos->iNumSector / iSectores;
			actual = ListaPedidos;
			pMin = aux;

		}
	}
	aux = ListaPedidos->Sgte;
	while (aux != actual) {
		if (Mayores) {

			fVariable = (float) aux->iNumSector / iSectores;

			//Busca los minimos mayores  al posicion actual;
			if ((min > fVariable) && (iPosicionCabezal <= aux->iNumSector)
					&& (aux->iUsado == 0)) {
				min = fVariable;
				pMin = aux;

			} //fin del if
		} else {
			//Busca los minimos menores  al posicion actual;
			if ((min > (aux->iNumSector) / iSectores)) {
				min = (float) (aux->iNumSector) / iSectores;
				pMin = aux;
				aux->iUsado = 1;
			} //fin del if;
		} //fin del if(mayores)
		aux = aux->Sgte;
	} //fin del while
	pMin->iUsado = 1;
	return pMin;

} //fin del fBuscarMinNodoLista
/******************************************************************************/
/* Nombre de Funcion: fAgregarPedido                                           */
/* Parametros: iSocket:socket                                                 */
/*             iSector: sectores del pedido                                   */
/*             itipoOp: tipo de operacion lectura o escritura                 */
/* Descripcion: Procedimiento que carga el nodo correspondiente a una pista   */
/*              pistas del disco                                              */
/******************************************************************************/
stNodoPedido * fSacarPedidosDeAlgunaCola(void) {

	if (iEstadoCola1 == ACTIVE) {

		return fSacarPedidoEnCola(lPista, 1);

	} else {
		return fSacarPedidoEnCola(lPista2, 2);
	} //fin dl if

} //findel fSacarPedidosDeAlgunaCola

/******************************************************************************/
/* Nombre de Funcion: fAgregarPedidosEnAlgunaCola                             */
/* Parametros: iSocket:socket                                                 */
/*             iSector: sectores del pedido                                   */
/*             itipoOp: tipo de operacion lectura o escritura                 */
/* Descripcion: Procedimiento que carga el nodo correspondiente a una pista   */
/*              pistas del disco                                              */
/******************************************************************************/
void fAgregarPedidoEnAlgunaCola(int iSocket, int iSector, int iTipoOp,
		char *sInfo, char *sDescriptorOriginal) {
	if (iEstadoCola1 == ACTIVE) {
		fAgregarPedido(iSocket, iSector, iTipoOp, sInfo, 2,
				sDescriptorOriginal);
	} else {
		fAgregarPedido(iSocket, iSector, iTipoOp, sInfo, 1,
				sDescriptorOriginal);
	} //fin del if
} //fin del fAgregarPedidosEnAlgunaCola

/********************************************************************************/
/* Nombre de Procedimiento: fCargarCache                                        */
/* Parametros:Sector: Sector que se va a cargar en la cache                     */
/*            sContenido:Contenido de 512 bytes que va a guardar en el vector   */
/* Descripcion: Funcion que se encarga de cargar en el vector de la cache       */
/*                un sector                                                     */
/********************************************************************************/
int fCargarCache(int iPista, int iSector, char *sContenido) {
//declaracion de variables locales
	int m = 0, posVieja = -1;
//fin de la declaracion de variables locales

	if (bCacheLLena) {
		posVieja = fBuscarSectoresInvalidos();
		if (posVieja == -1) {
			/*La cache esta llena  y no tiene sectores invalidos aplicamos la politica del LRU*/
			posVieja = fBuscarSectorMasViejo();
		}
		vecCache[posVieja].iPista = iPista;
		vecCache[posVieja].iNumSector = iSector;
		memset(vecCache[posVieja].info, 0, sizeof(vecCache[posVieja].info));
		strcpy(vecCache[posVieja].info, sContenido);
		ftime(&vecCache[posVieja].stTiempoActual);
	} else {
		while (vecCache[m].iNumSector != -1)
			m++;
		vecCache[m].iNumSector = iSector;
		strcpy(vecCache[m].info, sContenido);
		ftime(&vecCache[m].stTiempoActual);
		if (m == 10) {
			bCacheLLena = 1;
		}
	}
	return 1;
} //fin del fCargarCache

/********************************************************************************/
/* Nombre de Procedimiento: fBuscarSectorInvalidos                              */
/* Parametros:No recibe parametros					    						*/
/*																				*/
/* Descripcion: Funcion que se encarga de Buscar el sector que ha sido marcado  */
/*              como invalido                                                   */
/********************************************************************************/
int fBuscarSectoresInvalidos(void) {
	int pos;

	for (pos = 1; pos < 10; pos++) {
		if (vecCache[pos].iInvalido == 1) {
			return pos;
		} //fin del if
	} //fin del for
	return -1;
}

/********************************************************************************/
/* Nombre de Procedimiento: fBuscarSectorMasViejo                               */
/* Parametros:No recibe parametros												*/
/*																				*/
/* Descripcion: Funcion que se encarga de Buscar el sector que ha sido usado    */
/*                menos                                                         */
/********************************************************************************/
int fBuscarSectorMasViejo(void) {
	/*declaracion de variables locales*/
	struct timeb stHoraActual;
	long lTiempoEnMilisec, lMax, lActual;

	int pos, posViejo;

	/*fin de la declaracion de variables locales*/

	ftime(&stHoraActual);
	lTiempoEnMilisec = (long) (1000.0 * stHoraActual.time
			+ stHoraActual.millitm);
	lMax = lTiempoEnMilisec
			- (long) (1000.0 * vecCache[0].stTiempoActual.time
					+ vecCache[0].stTiempoActual.millitm);
	for (pos = 1; pos < 10; pos++) {
		lActual = lTiempoEnMilisec
				- (long) (1000.0 * vecCache[pos].stTiempoActual.time
						+ vecCache[pos].stTiempoActual.millitm);
		if (lActual > lMax) {
			lMax = lActual;
			posViejo = pos;
		} //fin del if;
	} //fin del for

	return posViejo;
} //fin del fBuscarSectorMasViejo

/********************************************************************************/
/* Nombre de Procedimiento: fBuscarEnCache                                      */
/* Parametros:	iSector: Sector al cual se busca en el vector de caches			*/
/*				sCadenaBuscada:Cadena que devuelve algo si lo encontro. 		*/
/* Descripcion: Funcion que se encarga de Buscar el sector de caches un sector. */
/*                Si lo encuentra lo devuelve el dato en la cadena buscada y    */
/*				retorna 1 sino retorna 0                                        */
/********************************************************************************/

int fBuscarEnCache(int iPista, int iSector, char * sCadenaBuscada,
		int iOperacion) {
	/*comienzo de variables locales*/
	int r;
	/*fin de la declaracion de variables locales*/
	if (iOperacion == 1) {
		memset(sCadenaBuscada, 0, 512);
		for (r = 0; r < 10; r++) {
			if ((vecCache[r].iNumSector == iSector)
					&& (vecCache[r].iPista == iPista)) {
				strcpy(sCadenaBuscada, vecCache[r].info);
				ftime(&vecCache[r].stTiempoActual);

				return 1;
			} //fin del if;
		} //fin del for
// iCacheMISS++;
	} else {
		for (r = 0; r < 10; r++) {
			if ((vecCache[r].iNumSector == iSector)
					&& (vecCache[r].iPista == iPista)) {
				vecCache[r].iInvalido = 1;
				return 1;
			} //fin del if;
		}
	} //fin del if;

	return 0;
} //fin del fBuscarEnCache

/********************************************************************************/
/* Nombre de Procedimiento: pArmadoTrace                                        */
/* Parametros:	stAux:estructura del pedido                         			*/
/*				origen de atendion del pedido* cache o disco             		*/
/*              ftiempo:tiempo de escritura o lectura.                          */
/*              stT:Estructura sTrace a cargar                                  */
/* Descripcion: Procedimiento que arma la estructura stTrace que sera envia al  */
/*              proc                                                            */
/********************************************************************************/
void pArmadoTrace(stNodoPedido *stAux, int iOrigen, float fTiempo, stTrace *stT,
		int iRPM) {
	/*Declaracion Variables locales*/
	int iSectARecorrer = 0, iPista, iMaxSector, iMinSector, i;
	int iCotaSuperior, iCotaInferior;
	char Lista[2000] = "\0";
	char ListaAux[1000] = "\0";
	char pos[10] = "\0";
	int iDif;
	float tie = 0.0;
	float tsect = 0.0;
	/*fin de la declaracion de variables locales*/

	iPista = ((int) (iPosicionCabezal / iSectores));

	/*Calculo el primer sector de la pista en la que esta el cabezal.*/
	iMinSector = (iPista * iSectores) + 1;
	/*calculo el maximo sector de la pista del cabezal */
	iMaxSector = (iPista + 1) * iSectores;
	tsect = (float) (60000.0 / (iRPM * iSectores));
	stT->iSectorAct = iPosicionCabezal;
	stT->iPistaAct = iPista;

	stT->iSectorPedido = stAux->iNumSector;
	stT->iPistaPedido = (int) ((stAux->iNumSector) / iSectores);
	stT->iSectorSig = (stAux->iNumSector) + 1;
	stT->iPistaSig = (int) (stT->iSectorSig / iSectores);

	if (iPosicionCabezal <= stAux->iNumSector) {
		iCotaInferior = iPosicionCabezal;
		iCotaSuperior = stAux->iNumSector;
		iDif = iCotaSuperior - iCotaInferior;
		stT->iCantSectoresRecorridos = iDif;

		for (i = iCotaInferior + 1; i <= iCotaSuperior; i++) {

			tie = tie + tsect;
			iPosicionCabezal++;

		} //fin del for
		if (iPosicionCabezal == iMaxSector) {
			iPosicionCabezal = iMinSector;
		} //fin del if

	} else {
		iCotaInferior = iPosicionCabezal;
		iCotaSuperior = iMaxSector;
		iDif = (iMaxSector - iPosicionCabezal)
				+ (stAux->iNumSector - iMinSector);

		stT->iCantSectoresRecorridos = iDif;
		for (i = iCotaInferior; i <= iCotaSuperior; i++) {

			tie = tie + tsect;
			iPosicionCabezal++;
		}
		iCotaInferior = iMinSector;
		iCotaSuperior = stAux->iNumSector;
		iPosicionCabezal = iMinSector;
		for (i = iCotaInferior; i <= iCotaSuperior; i++) {

			tie = tie + tsect;
			iPosicionCabezal++;
			tie = tie + tsect;
			iPosicionCabezal++;
		} //fin del for
	} //fin del if;

} //fin del pArmadoTrace

/********************************************************************************/
/* Nombre de Procedimiento: pPasarLogicoAFisico                                 */
/* Parametros:	iSector:SectorLogico                                			*/
/*				v:Estructura Fisica del sector                          		*/
/* Descripcion: Procedimiento que arma la estructura fisica de un sector        */
/********************************************************************************/

void pPasarLogicoAFisico(int iSector, vecTrace *v) {

	v->iPista = (int) iSector / iSectores;
	v->iSector = (iSector % iSectores);
} //fin del pPasarLogicoAFisico

